use std::fs;
use std::env;
use std::error::Error;

#[derive(Debug)]
pub struct Config {
    query: String,
    file: String,
    case_sensitive: bool,
}

pub fn parse_config(args: &[String]) -> Result<Config, &'static str> {
    if args.len() < 3 {
        return Err("Not enough arguments");
    }

    // case sensitive?
    let query = args[1].clone();
    let file = args[2].clone();

    let case_sensitive = env::var("CASE_INSENSITIVE").is_err();

    Ok(Config {query, file, case_sensitive})
}

fn read_file_content(path: &String) -> String {
    fs::read_to_string(path)
        .expect("Something went wrong when reading file")
}

pub fn usage(args: &[String]) {
    eprintln!("Usage: {} <query> <file>", args[0]);
}

pub fn run(config: Config) -> Result<(),Box<dyn Error>>{
    // read file content
    let content = fs::read_to_string(config.file)?;

    // read the env variable to determine search mode
    let result = match config.case_sensitive {
        true => search_sensitive(&config.query, &content),
        false => search_insensitive(&config.query, &content),
    };
    for line in result {
        println!("{}", line);
    }

    Ok(())
}

pub fn search_sensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str>{
    let mut result = Vec::new();
    for line in content.lines() {
        if line.contains(query) {
            result.push(line);
        }
    }
    result
}

pub fn search_insensitive<'a>(query: &str, content: &'a str) -> Vec<&'a str> {
    let iquery = query.to_lowercase();
    let mut result = Vec::new();

    for line in content.lines() {
        if line.to_lowercase().contains(&iquery) {
            result.push(line);
        }
    }

    result
}

#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn test_parse_config() {
        let args = vec![
            String::from(""),
            String::from("query"),
            String::from("file")
        ];
        let config = parse_config(&args).unwrap();
        assert_eq!(String::from("query"), config.query);
        assert_eq!(String::from("file"), config.file);
    }

    #[test]
    fn test_search() {
        let query = "duct";
        let content = "\
Rust:
safe, fast, productive.
Pick three.";
        assert!(content.contains(query));

        let m = search_sensitive(query, content);
        assert_eq!(1, m.len());
        assert_eq!("safe, fast, productive.", m[0]);
    }

    #[test]
    fn test_search_ignore_case() {
        let query = "rUsT";
        let content = "\
Rust:
safe, fast, productive.
Pick three.";
        let m = search_insensitive(query, content);
        assert_eq!(1, m.len());
        assert_eq!("Rust:", m[0]);
    }
}
